package com.ddddddl.zhangben.logic;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;

import android.content.Context;
import android.text.TextUtils;

import com.ddddddl.zhangben.data.Account;
import com.ddddddl.zhangben.data.AccountDAO;
import com.ddddddl.zhangben.data.Type;

public class AccountLogic extends BaseLogic {
	

	public static final String PARAM_TYPE = "PARAM_TYPE";

	private static AccountLogic accountLogic = new AccountLogic();
	
	private HashMap<Long, Type> mTypeMap = new HashMap<Long, Type>();
	private ArrayList<Type> mFirstTypes = new ArrayList<Type>();
	private ArrayList<Account> mAccounts = new ArrayList<Account>();
	private double mAccountAmountSum;
	private HashMap<Long, Double> mAmountMap = new HashMap<Long, Double>();
	private AccountDAO mAccountDAO;
	
	public static final int REQ_ACCOUNT_ADD = 0;
	public static final int REQ_TYPE_INIT = 1;
	public static final int REQ_ACCOUNT_LIST = 2;
	public static final int NOTIFY_AMOUNT_INIT = 3;
	public static final int NOTIFY_AMOUNT_SUM_INIT = 4;
	public static final int NOTIFY_AMOUNT_SUM_UPDATE = 5;
	public static final int NOTIFY_AMOUNT_UPDATE = 6;
	public static final int ACCOUNT_UPDATE = 7;
	public static final int REQ_ADD_TYPE = 8;
	public static final int REQ_UPDATE_TYPE = 9;
	public static final int NOTIFY_TYPE_UPDATE = 10;
	public static final String PARAM_ACCOUNT = "PARAM_ACCOUNT";
	public static final String PARAM_ACCOUNTS = "PARAM_ACCOUNT";
	public static final String PARAM_TYPE_MAP = "PARAM_ACCOUNT";
	public static final String PARAM_AMOUNT_MAP = "PARAM_ACCOUNT";
	public static final String PARAM_AMOUNT_SUM = "PARAM_ACCOUNT";
	public static final String PARAM_OLD_ACCOUNT = "PARAM_OLD_ACCOUNT";
	public static final String PARAM_NEW_ACCOUNT = "PARAM_NEW_ACCOUNT";
	public static final String PARAM_END_DATE = "PARAM_END_DATE";
	public static final String PARAM_START_DATE = "PARAM_START_DATE";
	public static final String PARAM_TYPE_NAME = "PARAM_TYPE_NAME";

	public static final String PARAM_SECOND_TYPE = "PARAM_SECOND_TYPE";


	
	private AccountLogic() {}
	
	public static AccountLogic getInstance() {
		return accountLogic;
	}
	
	public void setContext(Context context) {
		mAccountDAO = new AccountDAO(context);
	}
	
	private void addAccount(Account account) {
		mAccountDAO.addAccount(account);
		
		ExecuteMessage message = new ExecuteMessage(REQ_ACCOUNT_ADD);
		message.put(PARAM_ACCOUNT, account);
		notify(message);
		updateAmountGroupByType(account);
	}
	
	public void init() {
		if (mTypeMap.size() == 0) {
			ArrayList<Type> types = mAccountDAO.getTypes();
			for (Type type : types) {
				mTypeMap.put(type.id, type);
			}
			for (Type type : types) {
				if (type.pID != 0) {
					if (mTypeMap.get(type.pID).childType == null) {
						mTypeMap.get(type.pID).childType = new ArrayList<Type>();
					}
					mTypeMap.get(type.pID).childType.add(type);
				}
			}
			for (Entry<Long, Type> entry : mTypeMap.entrySet()) {
				Type type = entry.getValue();
				if (type.pID == 0) {
					mFirstTypes.add(type);
				}
			}
		}
	}
	
	public Type getType(long id) {
		return mTypeMap.get(id);
	}
	
	public ArrayList<Type> getFirstTypes() {
		return mFirstTypes;
	}
	
	private void getAccounts(Request request) {
		String startDate = request.getString(PARAM_START_DATE);
		String endDate = request.getString(PARAM_END_DATE);
		mAccounts = mAccountDAO.getAccounts(startDate, endDate);
		request.putResponseObject(PARAM_ACCOUNTS, mAccounts);
		
		getAmountGroupByType();
	}
	
	private void getAmountGroupByType() {
		if (mAccounts != null) {
			mAccountAmountSum = 0;
			for (Account account : mAccounts) {
				if (mAmountMap.get(account.firstType) == null) {
					mAmountMap.put(account.firstType, account.amount);
				} else {
					double amount = account.amount + mAmountMap.get(account.firstType);
					mAmountMap.put(account.firstType, amount);
				}
				mAccountAmountSum += account.amount;
			}
		}
		
		ExecuteMessage message1 = new ExecuteMessage(NOTIFY_AMOUNT_INIT);
		message1.put(PARAM_AMOUNT_MAP, mAmountMap);
		notify(message1);
		
		ExecuteMessage message2 = new ExecuteMessage(NOTIFY_AMOUNT_SUM_INIT);
		message2.putString(PARAM_AMOUNT_SUM, String.valueOf(mAccountAmountSum));
		notify(message2);
	}
	
	private void updateAmountGroupByType(Account account) {
		if (mAmountMap.get(account.firstType) == null) {
			mAmountMap.put(account.firstType, account.amount);
		} else {
			double amount = account.amount + mAmountMap.get(account.firstType);
			mAmountMap.put(account.firstType, amount);
		}
		mAccountAmountSum += account.amount;
		
		notifyAmountChange();
	}

	private void notifyAmountChange() {
		ExecuteMessage message1 = new ExecuteMessage(NOTIFY_AMOUNT_UPDATE);
		message1.put(PARAM_AMOUNT_MAP, mAmountMap);
		notify(message1);
		ExecuteMessage message2 = new ExecuteMessage(NOTIFY_AMOUNT_SUM_UPDATE);
		message2.putString(PARAM_AMOUNT_SUM, String.valueOf(mAccountAmountSum));
		notify(message2);
	}

	public void updateAccount(Request request) {
		Account newAccount = (Account) request.get(PARAM_NEW_ACCOUNT);
		Account oldAccount = (Account) request.get(PARAM_OLD_ACCOUNT);
		//1.�޸�DB
		mAccountDAO.updateAccount(newAccount);
		
		//2.�޸��߼����
		//��ȥ�����͵Ľ��
		double amount = mAmountMap.get(oldAccount.firstType) - oldAccount.amount;
		mAmountMap.put(oldAccount.firstType, amount);
		//���������͵Ľ��
		if (mAmountMap.get(newAccount.firstType) == null) {
			mAmountMap.put(newAccount.firstType, newAccount.amount);
		} else {
			amount = newAccount.amount + mAmountMap.get(newAccount.firstType);
			mAmountMap.put(newAccount.firstType, amount);
		}
		mAccountAmountSum += (newAccount.amount - oldAccount.amount);
		
		//3.֪ͨ������
		notifyAmountChange();
	}
	
	public void deleteAccount(Account account) {
		//1.�޸�DB
		mAccountDAO.deleteAccount(account);
		
		//2.�޸��߼����
		double amount = mAmountMap.get(account.firstType) - account.amount;
		mAmountMap.put(account.firstType, amount);
		
		//3.֪ͨ����
		notifyAmountChange();
	}

	@Override
	public void handlerRequest(Request request) {
		switch (request.type) {
		case REQ_TYPE_INIT:
			init();
			break;
		case REQ_ACCOUNT_ADD:
			Object object = request.get(PARAM_ACCOUNT);
			if (object instanceof Account) {
				addAccount((Account) object);
			}
			break;
		case REQ_ACCOUNT_LIST:
			getAccounts(request);
			break;
		case ACCOUNT_UPDATE:
			updateAccount(request);
			break;
		case REQ_ADD_TYPE:
			addType(request);
			break;
		case REQ_UPDATE_TYPE:
			updateType(request);
			break;
		default:
			break;
		}
	}

	public void addType(Request request) {
		String typeName = request.getString(PARAM_TYPE_NAME);
		Type type = new Type(typeName);
		long id = mAccountDAO.addType(type);
		type.id = id;
		request.putResponseObject(PARAM_TYPE, type);
	}
	
	public void updateType(Request request) {
		Type type = (Type) request.get(PARAM_TYPE);
		String secondTypeName = request.getString(PARAM_TYPE_NAME);
		mAccountDAO.updateType(type);
		mTypeMap.put(type.id, type);
		//只有修改一级类型的时候，才能为其增加二级类型，且二级类型的名称不能为空
		Type secondType = null;
		if (type.pID == Type.NO_PID && !TextUtils.isEmpty(secondTypeName)) {
			secondType = new Type(secondTypeName, type.id);
			secondType.id = mAccountDAO.addType(secondType);
			mTypeMap.put(secondType.id, secondType);
		}
		request.putResponseObject(PARAM_TYPE, type);
		request.putResponseObject(PARAM_SECOND_TYPE, secondType);
		
		ExecuteMessage message = new ExecuteMessage(NOTIFY_TYPE_UPDATE);
		notify(message);
	}
	
}
